package com.yachang.qym.usbhost.utils;

import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;

import com.yachang.qym.usbhost.UsbApplication;
import com.yachang.qym.usbhost.model.AreaModel;
import com.yachang.qym.usbhost.model.CalledModel;
import com.yachang.qym.usbhost.model.ContactModel;
import com.yachang.qym.usbhost.model.MachineInfoModel;
import com.yachang.qym.usbhost.model.RouteModel;
import com.yachang.qym.usbhost.usbserial.driver.UsbSerialPort;
import com.snappydb.DB;
import com.snappydb.SnappyDB;
import com.snappydb.SnappydbException;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


/**
 * Created by qinyuanmao on 16/1/15.
 */
public class GetDataFormUSB {

    private final int IS_CONTACT = 0;
    private final int IS_ROUTE = 1;
    private final int IS_CALLED = 2;
    private final int IS_AREA = 3;
    private final int IS_NOW_ROUTE = 4;
    private final int IS_MACHINE_INFO = 5;
    private final int IS_HELP_INFO = 6;
    private final int IS_MACHINE_ID = 7;
    private final int IS_TEST_NEW_DATA = 8;
    private int whatGoing;

    private int contactCount = 0;
    private int routeCount = 0;
    private int calledCount = 0;
    private int areaCount = 0;

    private byte[] myBuffer;
    private byte[] getBuffer = new byte[0];
    private boolean needToSend = false;

    private List<byte[]> contactDatas;
    private List<byte[]> routeDatas;
    private List<byte[]> calledDatas;
    private List<byte[]> areaData;
    private byte[] nowRoute;
    private byte[] machineInfoData;
    private byte[] helpInfoData;
    private byte[] machineIdData;
    private byte[] testNewData;

    private List<byte[]> byteContactList = new ArrayList<>();
    private List<byte[]> byteRouteList = new ArrayList<>();
    private List<byte[]> byteCalledList = new ArrayList<>();
    private List<byte[]> byteAreaList = new ArrayList<>();

    private UsbSerialPort sPort = null;

    private GetDataThread thread;

    private DataTransfer mDataTransfer = new DataTransfer(1024);
    private boolean threadCt = false;
    private DB snappydb;
    private ContactModel[] contactModelsDB;
    private CalledModel[] calledModelsDB;
    private RouteModel[] routeModelsDB;
    private AreaModel[] areaModelsDB;
    private MachineInfoModel machineInfoModelDB;

    private Handler mHandler = new Handler(){
        public void handleMessage(Message msg){
            switch (msg.what) {
                case IS_CONTACT : {
                    getContactByteList((byte[]) msg.obj);
                }break;
                case IS_ROUTE : {
                    getRouteByteList((byte[]) msg.obj);
                }break;
                case IS_CALLED : {
                    getCalledByteList((byte[]) msg.obj);
                }break;
                case IS_AREA : {
                    getAreaByteList((byte[]) msg.obj);
                }break;
                case IS_NOW_ROUTE : {
                    getNowRouteID((byte[]) msg.obj);
                }break;
                case IS_MACHINE_INFO : {
                    getMachineInfo((byte[]) msg.obj);
                }break;
                case IS_HELP_INFO : {
                    getHighInfo((byte[]) msg.obj);
                }break;
                case IS_MACHINE_ID : {
                    getMachineId((byte[]) msg.obj);
                }break;
                case IS_TEST_NEW_DATA : {
                    getTestNewData((byte[]) msg.obj);
                }break;
                default:break;
            }
            super.handleMessage(msg);
        }
    };

    public GetDataFormUSB(UsbSerialPort sPort, Context context){
        nowRoute = SendData.sendNowRoute();
        areaData = SendData.sendAreaData();
        routeDatas = SendData.sendRouteData();
        calledDatas = SendData.sendCalledData();
        contactDatas = SendData.sendContactData();
        machineInfoData = SendData.sendMachineInfo();
        helpInfoData = SendData.sendHighData();
        machineIdData = SendData.sendMachineId();
        testNewData = SendData.testNewData();

        this.sPort = sPort;

        try {
            snappydb = UsbApplication.getDB();
            contactModelsDB = snappydb.getObjectArray("contacts", ContactModel.class);
            calledModelsDB = snappydb.getObjectArray("calleds", CalledModel.class);
            routeModelsDB = snappydb.getObjectArray("routes", RouteModel.class);
            areaModelsDB = snappydb.getObjectArray("areas", AreaModel.class);
            machineInfoModelDB = snappydb.get("machineInfo", MachineInfoModel.class);
        } catch (SnappydbException e) {
            e.printStackTrace();
           //c NotificationCenter.getInstance().postNotification("isNewData");
        }

        threadCt = true;
        if (thread != null){
            thread = null;
        }
        thread = new GetDataThread();
        thread.start();
    }

    public void sendTestNewData() {
        whatGoing = IS_TEST_NEW_DATA;
        myBuffer = testNewData;
        needToSend = true;
    }

    public void getTestNewData(byte data[]) {
        if(data[7] == 0) {
            NotificationCenter.getInstance().postNotification("isNewData");
        } else {
            try {
                snappydb.close();
                snappydb.destroy();
                snappydb = new SnappyDB.Builder(UsbApplication.getContext())
                        .directory(Environment.getExternalStorageDirectory().getAbsolutePath()) //optional
                        .name("yachang")//optional
                        .build();
                UsbApplication.snappydb = snappydb;
                clearDBData();
                NotificationCenter.getInstance().postNotification("isNewData");
            } catch (SnappydbException e) {
                try {
                    snappydb.destroy();
                    snappydb = new SnappyDB.Builder(UsbApplication.getContext())
                            .directory(Environment.getExternalStorageDirectory().getAbsolutePath()) //optional
                            .name("yachang")//optional
                            .build();
                    clearDBData();
                    NotificationCenter.getInstance().postNotification("isNewData");
                } catch (SnappydbException e1) {
                    NotificationCenter.getInstance().postNotification("isNewData");
                    e1.printStackTrace();
                }
                NotificationCenter.getInstance().postNotification("isNewData");
                e.printStackTrace();
            }
        }
    }

    private void clearDBData(){
        contactModelsDB = null;
        calledModelsDB = null;
        routeModelsDB = null;
        areaModelsDB = null;
        machineInfoModelDB = null;
    }

    public void sendContactData(){
        if(contactModelsDB == null){
            if (contactCount == 128) {
                try {
                    AllData.contactModels.clear();
                    AllData.contactModels.addAll(DataTransfer.getContactList(byteContactList));
                    NotificationCenter.getInstance().postNotification("contactFinish");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            } else {
                whatGoing = IS_CONTACT;
                myBuffer = contactDatas.get(contactCount++);
                needToSend = true;
            }
        } else {
            AllData.contactModels.clear();
            AllData.contactModels.addAll(Arrays.asList(contactModelsDB));
            NotificationCenter.getInstance().postNotification("contactFinish");
        }
    }

    public void getContactByteList(byte data[]){
        int what = (int) data[6] >= 0 ? (int) data[6] : 256 + (int) data[6];
        if (what == 0xFA) {
            try {
                AllData.contactModels.clear();
                AllData.contactModels.addAll(DataTransfer.getContactList(byteContactList));
                Object[] contactModels = AllData.contactModels.toArray();
                snappydb.put("contacts", contactModels);
                NotificationCenter.getInstance().postNotification("contactFinish");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (SnappydbException e) {
                e.printStackTrace();
            }
        } else {
            byteContactList.add(data);
            sendContactData();
        }
    }

    public void sendCalledData(){
        if(calledModelsDB == null){
            if (calledCount == 128) {
                try {
                    AllData.calledModels.clear();
                    AllData.calledModels.addAll(DataTransfer.getCalledsList(byteCalledList));
                    NotificationCenter.getInstance().postNotification("calledFinish");
                }
                catch (UnsupportedEncodingException e){
                    e.printStackTrace();
                }
            } else {
                whatGoing = IS_CALLED;
                myBuffer = calledDatas.get(calledCount++);
                needToSend = true;
            }
        }else {
            AllData.calledModels.clear();
            AllData.calledModels.addAll(Arrays.asList(calledModelsDB));
            NotificationCenter.getInstance().postNotification("calledFinish");
        }
    }

    public void getCalledByteList(byte[] data){
        int what = (int) data[6] >= 0 ? (int) data[6] : 256 + (int) data[6];
        if(what == 0xFA){
            try {
                AllData.calledModels.clear();
                AllData.calledModels.addAll(DataTransfer.getCalledsList(byteCalledList));
                NotificationCenter.getInstance().postNotification("calledFinish");
                Object[] calledModels = AllData.calledModels.toArray();
                snappydb.put("calleds", calledModels);
            }
            catch (UnsupportedEncodingException e){
                e.printStackTrace();
            } catch (SnappydbException e) {
                e.printStackTrace();
            }
        }else {
            byteCalledList.add(data);
            sendCalledData();
        }
    }

    public void sendRouteData(){
        if(routeModelsDB == null) {
            if (routeCount == 128) {
                try {
                    AllData.routeModels.clear();
                    AllData.routeModels.addAll(DataTransfer.getDMRRoute(byteRouteList));
                    NotificationCenter.getInstance().postNotification("routeFinish");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            } else {
                whatGoing = IS_ROUTE;
                myBuffer = routeDatas.get(routeCount++);
                needToSend = true;
            }
        }else {
            AllData.routeModels.clear();
            AllData.routeModels.addAll(Arrays.asList(routeModelsDB));
            NotificationCenter.getInstance().postNotification("routeFinish");
        }
    }

    public void getRouteByteList(byte[] data){
        int what = (int) data[6] > 0 ? data[6] : 256 + data[6];
        if(what == 0xFA){
            try {
                AllData.routeModels.clear();
                AllData.routeModels.addAll(DataTransfer.getDMRRoute(byteRouteList));
                Object[] routeModels = AllData.routeModels.toArray();
                snappydb.put("routes", routeModels);
                NotificationCenter.getInstance().postNotification("routeFinish");
            }
            catch (UnsupportedEncodingException e){
                e.printStackTrace();
            } catch (SnappydbException e) {
                e.printStackTrace();
            }
        }else {
            byteRouteList.add(data);
            sendRouteData();
        }
    }

    public void sendAreaData(){
        if(areaModelsDB == null) {
            if (areaCount == 16) {
                try {
                    AllData.areaModels.clear();
                    AllData.areaModels.addAll(DataTransfer.getAreaList(byteAreaList));
                    NotificationCenter.getInstance().postNotification("areaFinish");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            } else {
                whatGoing = IS_AREA;
                myBuffer = areaData.get(areaCount++);
                needToSend = true;
            }
        }else {
            AllData.areaModels.clear();
            AllData.areaModels.addAll(Arrays.asList(areaModelsDB));
            NotificationCenter.getInstance().postNotification("areaFinish");
        }
    }

    public void getAreaByteList(byte[] data){
        int what = (int) data[6] >= 0 ? data[6] : 256 + data[6];
        if(what == 0xFA){
            try {
                AllData.areaModels.clear();
                AllData.areaModels.addAll(DataTransfer.getAreaList(byteAreaList));
                Object[] areaModels = AllData.areaModels.toArray();
                snappydb.put("areas", areaModels);
                NotificationCenter.getInstance().postNotification("areaFinish");
            }
            catch (UnsupportedEncodingException e){
                e.printStackTrace();
            } catch (SnappydbException e) {
                e.printStackTrace();
            }
        }else {
            byteAreaList.add(data);
            sendAreaData();
        }
    }

    public void sendMachineInfo() {
        if(machineInfoModelDB == null) {
            whatGoing = IS_MACHINE_INFO;
            myBuffer = machineInfoData;
            needToSend = true;
        } else {
            AllData.machineInfo = machineInfoModelDB;
            NotificationCenter.getInstance().postNotification("machineInfoFinish");
        }
    }

    public void getMachineInfo(byte[] data){
        try {
            AllData.machineInfo = DataTransfer.getMachineInfo(data);
            snappydb.put("machineInfo", AllData.machineInfo);
            NotificationCenter.getInstance().postNotification("machineInfoFinish");
        }catch (UnsupportedEncodingException e){
            e.printStackTrace();
        } catch (SnappydbException e) {
            e.printStackTrace();
        }
    }

    public void sendNowRoute() {
        whatGoing = IS_NOW_ROUTE;
        myBuffer = nowRoute;
        needToSend = true;
    }

    public void getNowRouteID(byte[] data) {
        try {
            AllData.nowRoute = DataTransfer.getNowRoute(data);
            NotificationCenter.getInstance().postNotification("nowRouteFinish");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    public void sendMachineId() {
        whatGoing = IS_MACHINE_ID;
        myBuffer = machineIdData;
        needToSend = true;
    }

    public void getMachineId(byte[] data) {
        try {
            AllData.machineId = DataTransfer.getMachineId(data);
            snappydb.put("machineId", AllData.machineId);
            NotificationCenter.getInstance().postNotification("machineIdFinish");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (SnappydbException e) {
            e.printStackTrace();
        }
    }

    public void sendHighInfo() {
        whatGoing = IS_HELP_INFO;
        myBuffer = helpInfoData;
        needToSend = true;
    }

    public void getHighInfo(byte[] data) {
        NotificationCenter.getInstance().postNotification("HelpInfoFinish");
    }

    class GetDataThread extends Thread {

        int count = 0;

        public void run(){
            while (threadCt) {
                if(needToSend){
                    needToSend = false;
                    try {
                        sPort.write(myBuffer, 30);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                byte[] buffer = new byte[256];
                int dataLength = 0;
                try {
                    dataLength = sPort.read(buffer, buffer.length);
                } catch (IOException e) {
                    e.printStackTrace();
                }

                count ++;
                if (dataLength > 0) {
                    getData(buffer, dataLength);
                }

                if(count > 8){
                    count = 0;
                    needToSend = true;
                    getBuffer = new byte[0];
                }
            }
        }

        public void getData(byte[] buffer, int dataLength) {

            mDataTransfer.AddData(buffer, dataLength);
            byte[] newBuffer = new byte[mDataTransfer.GetDataLen()];
            mDataTransfer.ReadMultiData(newBuffer, mDataTransfer.GetDataLen());

            byte[] data = new byte[getBuffer.length + newBuffer.length];
            System.arraycopy(getBuffer, 0, data, 0, getBuffer.length);
            System.arraycopy(newBuffer, 0, data, getBuffer.length, newBuffer.length);
            getBuffer = data;
            LogUtil.LogByte(getBuffer);
            int byte0 = (int) getBuffer[0] > 0 ? (int) getBuffer[0] : (int) getBuffer[0] + 256;
            int byte1 = (int) getBuffer[1] > 0 ? (int) getBuffer[1] : (int) getBuffer[1] + 256;
            int byte2 = (int) getBuffer[2] > 0 ? (int) getBuffer[2] : (int) getBuffer[2] + 256;
            if (byte0 != 0x84 && byte1 != 0xA9 && byte2 != 61) {
                getBuffer = new byte[0];
                count = 0;
            } else{
                if (getBuffer.length >= 10) {
                    int bufferDataLength = ((int) getBuffer[4]) > 0 ? ((int) getBuffer[4]) : (((int) getBuffer[4]) + 256);
                    if (getBuffer.length >= bufferDataLength + 5) {
                        count = 0;
                        Message message = new Message();
                        message.obj = getBuffer;
                        switch (whatGoing) {
                            case IS_AREA:
                                message.what = IS_AREA;
                                break;
                            case IS_CALLED:
                                message.what = IS_CALLED;
                                break;
                            case IS_ROUTE:
                                message.what = IS_ROUTE;
                                break;
                            case IS_CONTACT:
                                message.what = IS_CONTACT;
                                break;
                            case IS_NOW_ROUTE :
                                message.what = IS_NOW_ROUTE;
                                break;
                            case IS_MACHINE_INFO :
                                message.what = IS_MACHINE_INFO;
                                break;
                            case IS_MACHINE_ID :
                                message.what = IS_MACHINE_ID;
                                break;
                            case IS_HELP_INFO :
                                message.what = IS_HELP_INFO;
                                threadCt = false;
                                break;
                            case IS_TEST_NEW_DATA :
                                message.what = IS_TEST_NEW_DATA;
                                break;
                            default:return;
                        }
                        getBuffer = new byte[0];
                        mHandler.sendMessage(message);
                    }
                }
            }

        }
    }
}
